package com.link.base.core.basic.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.link.base.user.model.CoreUser;
import com.link.core.cllog.LCLogger;
import com.link.base.wechat.basic.util.WeixinHttpUtil;
import com.link.core.basic.service.BasicServiceException;
import com.link.core.util.PropertyUtil;
import com.link.core.util.RedisUtil;
import com.link.core.util.StringUtils;
import com.link.core.util.UserUtil;
import com.link.core.util.redisclient.LinkRedisClient;
import net.sf.jmimemagic.Magic;
import net.sf.jmimemagic.MagicMatch;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;


public class TDCUtil {

    private static final Logger logger = LogManager.getLogger(TDCUtil.class);

    public static final String CLIENT_ID = PropertyUtil.getCommonProperty("tdc_client_id");

    public static final String CLIENT_SECRET = PropertyUtil.getCommonProperty("tdc_client_secret");

    public static final String REFRESH_TOKEN = PropertyUtil.getCommonProperty("tdc_refresh_token");

    public static final String ACCESS_TOKEN = PropertyUtil.getCommonProperty("tdc_access_token");

    public static final String AUTH_CODE = PropertyUtil.getCommonProperty("tdc_auth_code");

    public static final String REDIRECT_URI = PropertyUtil.getCommonProperty("tdc_redirect_uri");

    public static final String ACCOUNT_ID = PropertyUtil.getCommonProperty("tdc_account_id");

    public static final String TENCENT_TOKEN_URL = "https://api.e.qq.com/oauth/token";

    public String getAccessToken() throws Exception {
        //先去redis里拿AccessCode
        LinkRedisClient jedis = RedisUtil.getJedis();
        String accessToken = jedis.get("tdc_access_token");
        String authCode = PropertyUtil.getCommonProperty("tdc_auth_code");
        try {
            if (StringUtils.isBlank(accessToken)) {
                // 获取refreshToken
                String refreshToken = jedis.get("tbc_refresh_token");
                if (StringUtils.isBlank(refreshToken)) {
                    String getRefreshTokenByAuthCode = TENCENT_TOKEN_URL + "?client_id=" + CLIENT_ID
                            + "&client_secret=" + CLIENT_SECRET
                            + "&grant_type=authorization_code&authorization_code=" + authCode + "&redirect_uri=" + REDIRECT_URI;
                    JSONObject refreshObject = WeixinHttpUtil.doGet(getRefreshTokenByAuthCode);
                    if (refreshObject != null && refreshObject.getJSONObject("data") != null) {
                        refreshToken = refreshObject.getJSONObject("data").getString("refresh_token");
                        accessToken = refreshObject.getJSONObject("data").getString("access_token");
                        if (StringUtils.isNotBlank(refreshToken) && StringUtils.isNotBlank(accessToken)) {
                            loadTokenToRedis("tdc_refresh_token",refreshToken,2592000);
                            loadTokenToRedis("tdc_access_token",accessToken,86400);
                        } else {
                            refreshToken = PropertyUtil.getCommonProperty("tdc_refresh_token");
                        }
                    } else {
                        refreshToken = PropertyUtil.getCommonProperty("tdc_refresh_token");
                    }
                }
                //利用refreshToken刷accessToken
                String getAccessTokenByRefreshUrl = TENCENT_TOKEN_URL + "?client_id=" + CLIENT_ID
                        + "&client_secret=" + CLIENT_SECRET
                        + "&grant_type=refresh_token&refresh_token=" + refreshToken + "&redirect_uri=" + REDIRECT_URI;
                JSONObject jsonObject = WeixinHttpUtil.doGet(getAccessTokenByRefreshUrl);
                if (jsonObject != null && jsonObject.getJSONObject("data") != null) {
                    accessToken = jsonObject.getJSONObject("data").getString("access_token");
                    loadTokenToRedis("tdc_refresh_token",refreshToken,2592000);
                    loadTokenToRedis("tdc_access_token",accessToken,86400);
                } else {
                    throw new BasicServiceException("通过refreshToken" + refreshToken + "获取API相应参数失败！");
                }
            }
        } catch (Exception e) {
            throw e;
        } finally {
            RedisUtil.returnResource(jedis);
        }
        return accessToken;
    }

    public static String refreshAccessToken() throws Exception {
        //先去redis里拿AccessCode
        LinkRedisClient jedis = RedisUtil.getJedis();
        String accessToken = null;
        try {
            // 获取refreshToken
            String refreshToken = jedis.get("tbc_refresh_token");
            String authCode = PropertyUtil.getCommonProperty("tdc_auth_code");
            if (StringUtils.isBlank(refreshToken)) {
                String getRefreshTokenByAuthCode = TENCENT_TOKEN_URL + "?client_id=" + CLIENT_ID
                        + "&client_secret=" + CLIENT_SECRET
                        + "&grant_type=authorization_code&authorization_code=" + authCode + "&redirect_uri=" + REDIRECT_URI;
                JSONObject refreshObject = WeixinHttpUtil.doGet(getRefreshTokenByAuthCode);
                if (refreshObject != null && refreshObject.getJSONObject("data") != null) {
                    refreshToken = refreshObject.getJSONObject("data").getString("refresh_token");
                    accessToken = refreshObject.getJSONObject("data").getString("access_token");
                    if (StringUtils.isNotBlank(refreshToken) && StringUtils.isNotBlank(accessToken)) {
                        loadTokenToRedis("tdc_refresh_token",refreshToken,2592000);
                        loadTokenToRedis("tdc_access_token",accessToken,86400);
                    } else {
                        refreshToken = PropertyUtil.getCommonProperty("tdc_refresh_token");
                    }
                } else {
                    refreshToken = PropertyUtil.getCommonProperty("tdc_refresh_token");
                }
            }
            //利用refreshToken刷accessToken
            String getAccessTokenByRefreshUrl = TENCENT_TOKEN_URL + "?client_id=" + CLIENT_ID
                    + "&client_secret=" + CLIENT_SECRET
                    + "&grant_type=refresh_token&refresh_token=" + refreshToken + "&redirect_uri=" + REDIRECT_URI;
            JSONObject jsonObject = WeixinHttpUtil.doGet(getAccessTokenByRefreshUrl);
            if (jsonObject != null && jsonObject.getJSONObject("data") != null) {
                accessToken = jsonObject.getJSONObject("data").getString("access_token");
                loadTokenToRedis("tdc_refresh_token",refreshToken,2592000);
                loadTokenToRedis("tdc_access_token",accessToken,86400);
            } else {
                throw new BasicServiceException("通过refreshToken" + refreshToken + "获取API相应参数失败！");
            }
        } catch (Exception e) {
            throw e;
        } finally {
            RedisUtil.returnResource(jedis);
        }
        return accessToken;
    }

    public static void loadTokenToRedis(String key, String tokenValue,int num) throws Exception {
        LinkRedisClient jedis = RedisUtil.getJedis();
        try {
            CoreUser user = UserUtil.getUser();
            jedis.del(key);
            jedis.set(key, tokenValue,"NX", "EX", num);
        } catch (Exception e) {
            throw e;
        } finally {
            RedisUtil.returnResource(jedis);
        }
    }

    /**
     * MD5 32位加密
     *
     * @author 秦学刚
     * @param str 加密字符串
     * @date 2019/03/25
     */
    public String encryption(String str) throws Exception {
        String result = str;
        String re_md5 = new String();
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(result.getBytes());
            byte[] b = md.digest();
            int i;
            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0) {
                    i += 256;
                }
                if (i < 16) {
                    buf.append("0");
                }
                buf.append(Integer.toHexString(i));
            }
            re_md5 = buf.toString();
        } catch (NoSuchAlgorithmException e) {
            LCLogger.withException(e);
        }
        return re_md5.toUpperCase();
    }

    /**
     * 上传附件
     *
     * @param urlStr  访问地址
     * @param textMap 参数
     * @param fileMap 附件参数
     * @return
     */
    public static JSONObject formUpload(String urlStr, Map<String, String> textMap, Map<String, String> fileMap) throws Exception {
        String res = "";
        HttpURLConnection conn = null;
        DataInputStream in = null;
        String BOUNDARY = "---------------------------123821742118716"; //boundary就是request头和上传文件内容的分隔符
        try {
            URL url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(30000);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);

            OutputStream out = new DataOutputStream(conn.getOutputStream());
            // text
            if (textMap != null) {
                StringBuffer strBuf = new StringBuffer();
                Iterator<Map.Entry<String, String>> iter = textMap.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry<String, String> entry = iter.next();
                    String inputName = (String) entry.getKey();
                    String inputValue = (String) entry.getValue();
                    if (inputValue == null) {
                        continue;
                    }
                    strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
                    strBuf.append("Content-Disposition: form-data; name=\"" + inputName + "\"\r\n\r\n");
                    strBuf.append(inputValue);
                }
                out.write(strBuf.toString().getBytes());
            }

            // file
            if (fileMap != null) {
                Iterator<Map.Entry<String, String>> iter = fileMap.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry<String, String> entry = iter.next();
                    String inputName = (String) entry.getKey();
                    String inputValue = (String) entry.getValue();
                    if (inputValue == null) {
                        continue;
                    }
                    File file = new File(inputValue);
                    String filename = file.getName();
                    MagicMatch match = Magic.getMagicMatch(file, false, true);
                    String contentType = match.getMimeType();

                    StringBuffer strBuf = new StringBuffer();
                    strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
                    strBuf.append("Content-Disposition: form-data; name=\"" + inputName + "\"; filename=\"" + filename + "\"\r\n");
                    strBuf.append("Content-Type:" + contentType + "\r\n\r\n");

                    out.write(strBuf.toString().getBytes());

                    in = new DataInputStream(new FileInputStream(file));
                    int bytes = 0;
                    byte[] bufferOut = new byte[1024];
                    while ((bytes = in.read(bufferOut)) != -1) {
                        out.write(bufferOut, 0, bytes);
                    }
                    in.close();
                }
            }

            byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
            out.write(endData);
            out.flush();
            out.close();

            // 读取返回数据
            StringBuffer strBuf = new StringBuffer();
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                strBuf.append(line).append("\n");
            }
            res = strBuf.toString();
            reader.close();
            reader = null;
        } catch (Exception e) {
            System.out.println("发送POST请求出错。" + urlStr);
            LCLogger.withException(e);
        } finally {
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
            if (in != null) {
                in.close();
            }
        }
        return JSON.parseObject(res);
    }

    public static void main(String[] args) throws Exception {
        // 通过authorization_code获取token
        String token = "39a268bdfc9420a827b368a0b8f23275";
        System.out.println(token);
        String accountId = "9883979";
        //  创建一个人群
        Map<String, String> paramMap = new HashMap<String, String>(16);
        paramMap.put("account_id", accountId);
        paramMap.put("name", "测试WXOpenId包");
        paramMap.put("description", "测试WXOpenId包");
        paramMap.put("type", "CUSTOMER_FILE");
        Object data = JSON.toJSON(paramMap);
        JSONObject json = WeixinHttpUtil.doPost("https://api.e.qq.com/v1.0/custom_audiences/add?access_token="
                + token + "&timestamp=" + System.currentTimeMillis() / 1000 + "&nonce=" + UUID.randomUUID().toString().replace("-", ""), data);
        System.out.println(json);
        String audienceId = json.getJSONObject("data").getString("audience_id");
        Map<String, String> params = new HashMap<String, String>(16);
        params.put("account_id", accountId);
        params.put("audience_id", audienceId);
        params.put("user_id_type", "WECHAT_OPENID");
        params.put("open_app_id","wx0f55badcd4fe002c");
        Map<String, String> fileMap = new HashMap<String, String>();
        fileMap.put("file", "D:\\testtdc\\开盖扫码openid.txt");
        JSONObject result = formUpload("https://api.e.qq.com/v1.1/custom_audience_files/add?access_token="
                + token + "&timestamp=" + System.currentTimeMillis() / 1000 + "&nonce="
                + UUID.randomUUID().toString().replace("-", ""), params, fileMap);
        System.out.println(result);
    }

    /**
     * 新建一个人群
     * @author yangxiaolin
     * @date 2019/05/23 16:59
     * @param name 人群名
     * @param comment 备注
     */
    public Map<String, Object> addCustomGroup(String name,String comment) throws Exception {
        Map<String,Object> result = new HashMap<>(4);
        String token = getAccessToken();
        Map<String, String> paramMap = new HashMap<String, String>(4);
        paramMap.put("account_id", ACCOUNT_ID);
        paramMap.put("name", name);
        paramMap.put("description", comment);
        paramMap.put("type", "CUSTOMER_FILE");
        Object data = JSON.toJSON(paramMap);
        JSONObject json = WeixinHttpUtil.doPost("https://api.e.qq.com/v1.0/custom_audiences/add?access_token="
                + token + "&timestamp=" + System.currentTimeMillis() / 1000 + "&nonce=" + UUID.randomUUID().toString().replace("-", ""), data);
        if (json != null) {
            String code = json.getString("code");
            String message = json.getString("message");
            JSONObject resultData = json.getJSONObject("data");
            String audienceId = "";
            if (resultData != null) {
                audienceId = resultData.getString("audience_id");
            }
            result.put("code", code);
            result.put("message", message);
            result.put("audience_id",audienceId);
        } else {
            result.put("code", 11405);
            result.put("message", "无法获取接口返回信息，请查证后再试！");
            result.put("audience_id","");
        }
        return result;
    }

    /**
     * 为某个人群上传人群数据
     * @author yangxiaolin
     * @date 2019/05/23 16:59
     * @param audienceId 人群名Id
     * @param type 上传的数据类型
     * @param fileUrl 文件路径
     */
    public Map<String, Object> uploadCustomFile(String audienceId,String type,String fileUrl,String opType,String openAppId) throws Exception {
        Map<String,Object> result = new HashMap<>(4);
        if (StringUtils.isBlank(audienceId)) {
            throw new BasicServiceException("调用TDC人群文件上传接口，人群包Id不能为空！");
        }
        if (StringUtils.isBlank(type)) {
            throw new BasicServiceException("调用TDC人群文件上传接口，文件类型不能为空！");
        }
        if (StringUtils.isBlank(fileUrl)) {
            throw new BasicServiceException("调用TDC人群文件上传接口，文件路径不能为空！");
        }
        if (StringUtils.isBlank(opType)) {
            opType = "APPEND";
        }
        String token = getAccessToken();
        Map<String, String> params = new HashMap<String, String>(4);
        params.put("account_id", ACCOUNT_ID);
        params.put("audience_id", audienceId);
        params.put("user_id_type", type);
        params.put("operation_type",opType);
        if ("WECHAT_OPENID".equals(type) || "MOBILE_QQ_OPENID".equals(type)) {
            if (StringUtils.isBlank(openAppId)) {
                throw new BasicServiceException("当人群数据类型为" + type + "时，openAppId不能为空！");
            }
            params.put("open_app_id",openAppId);
        }
        Map<String, String> fileMap = new HashMap<String, String>();
        fileMap.put("file", fileUrl);
        JSONObject json = formUpload("https://api.e.qq.com/v1.1/custom_audience_files/add?access_token="
                + token + "&timestamp=" + System.currentTimeMillis() / 1000 + "&nonce="
                + UUID.randomUUID().toString().replace("-", ""), params, fileMap);
        if (json != null) {
            String code = json.getString("code");
            String message = json.getString("message");
            JSONObject resultData = json.getJSONObject("data");
            String cusAudFileId = "";
            if (resultData != null) {
                cusAudFileId = resultData.getString("custom_audience_file_id");
            }
            result.put("code", code);
            result.put("message", message);
            result.put("custom_audience_file_id",cusAudFileId);
        } else {
            result.put("code", "11405");
            result.put("message", "无法获取接口返回信息，请查证后再试！");
            result.put("custom_audience_file_id","");
        }
        return result;
    }

}
